﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
namespace Infrastructure.UI
{
    /// <summary>
    /// GraphicsControl 的摘要说明。
    /// </summary>
    public class GraphicsControl
    {

        #region API Constants
        /// <summary>
        /// API Constants
        /// </summary>
        private const uint SHGFI_ICON = 0x100;	// get icon
        private const uint SHGFI_LINKOVERLAY = 0x8000;	// put a link overlay on icon
        private const uint SHGFI_SELECTED = 0x10000;	// show icon in selected state
        private const uint SHGFI_LARGEICON = 0x0;		// get large icon
        private const uint SHGFI_SMALLICON = 0x1;		// get small icon
        private const uint SHGFI_OPENICON = 0x2;		// get open icon
        private const uint SHGFI_SHELLICONSIZE = 0x4;		// get shell size icon
        private const uint SHGFI_USEFILEATTRIBUTES = 0x10;		// use passed dwFileAttribute
        private const uint SHGFI_TYPENAME = 0x400;	// get file type name

        /// <summary>
        /// A SHFILEINFO structure used to extract the icon resource of a file or folder.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct SHFILEINFO
        {
            public IntPtr hIcon;
            public IntPtr iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        };

        /// <summary>
        /// A BITMAPINFO stucture used to store an alphablended bitmap for adding to imagelist.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private class BITMAPINFO
        {
            public Int32 biSize;
            public Int32 biWidth;
            public Int32 biHeight;
            public Int16 biPlanes;
            public Int16 biBitCount;
            public Int32 biCompression = 0;
            public Int32 biSizeImage = 0;
            public Int32 biXPelsPerMeter = 0;
            public Int32 biYPelsPerMeter = 0;
            public Int32 biClrUsed = 0;
            public Int32 biClrImportant = 0;
            public Int32 colors = 0;
        };

        [DllImport("comctl32.dll")]
        private static extern bool ImageList_Add(IntPtr hImageList, IntPtr hBitmap, IntPtr hMask);
        [DllImport("kernel32.dll")]
        private static extern bool RtlMoveMemory(IntPtr dest, IntPtr source, int dwcount);
        [DllImport("shell32.dll")]
        private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
        [DllImport("user32.dll")]
        private static extern IntPtr DestroyIcon(IntPtr hIcon);
        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateDIBSection(IntPtr hdc, [In, MarshalAs(UnmanagedType.LPStruct)]BITMAPINFO pbmi, uint iUsage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        public GraphicsControl()
        {

        }
        private static GraphicsControl _instance;
        public static GraphicsControl Instance
        {
            get { return _instance ?? (_instance = new GraphicsControl()); }
        }

        #endregion

        #region Add Water Mark to Image

        /**/
        /// <summary>
        /// Draw WaterMark to Src Image
        /// </summary>
        /// <param name="srcImage">Src Image</param>
        /// <param name="waterMark">WaterMark Image</param>
        /// <param name="x">WaterMark's Location X</param>
        /// <param name="y">WaterMark's Location Y</param>
        /// <returns>Image</returns>
        public Image DrawWaterMark(Image srcImage, Image waterMark, int x, int y)
        {
            Graphics g = Graphics.FromImage(srcImage);

            g.DrawImage(waterMark, x, y);

            g.Dispose();
            return srcImage;
        }

        /// <summary>
        /// Draw WaterMark to Src Image
        /// </summary>
        /// <param name="srcImage">Src Image</param>
        /// <param name="waterMark">WaterMark Image</param>
        /// <param name="x">WaterMark's Location X</param>
        /// <param name="y">WaterMark's Location Y</param>
        /// <param name="alphaRate">WaterMark's alpha rate, 0 to 255, 0 means total transparent, 255 means don't transparent</param>
        /// <returns>Image</returns>
        public Image DrawWaterMark(Image srcImage, Image waterMark, int x, int y, int alphaRate)
        {
            Graphics g = Graphics.FromImage(srcImage);

            if (alphaRate < 0 || alphaRate > 255)
                alphaRate = 255;

            //Transfer Image to Bitmap to Get Pixel
            Bitmap bmWaterMark = new Bitmap(waterMark);

            for (int ix = 0; ix < waterMark.Width; ix++)
            {
                for (int iy = 0; iy < waterMark.Height; iy++)
                {
                    int ir = bmWaterMark.GetPixel(ix, iy).R;
                    int ig = bmWaterMark.GetPixel(ix, iy).G;
                    int ib = bmWaterMark.GetPixel(ix, iy).B;

                    g.DrawEllipse(new Pen(new SolidBrush(Color.FromArgb(alphaRate, ir, ig, ib))), x + ix, y + iy, 1, 1);
                }
            }

            g.Dispose();
            return srcImage;
        }
      
        #endregion


        #region Image Postion
        /**/
        /// <summary>
        /// Draw WaterMark to Src Image
        /// </summary>
        /// <param name="srcImage">Src Image</param>
        /// <param name="waterMark">WaterMark Image</param>
        /// <param name="oPosition">WaterMark's position</param>
        /// <returns>Image</returns>
        public Image DrawWaterMark(Image srcImage, Image waterMark, ImagePostion oPosition)
        {
            int x = 0;
            int y = 0;

            #region Switch Postion get X and Y
            switch (oPosition)
            {
                case ImagePostion.TopLeft:
                    x = 0;
                    y = 0;
                    break;
                case ImagePostion.TopCenter:
                    x = (srcImage.Width / 2) - (waterMark.Width / 2);
                    y = 0;
                    break;
                case ImagePostion.TopRight:
                    x = srcImage.Width - waterMark.Width;
                    y = 0;
                    break;
                case ImagePostion.MiddleLeft:
                    x = 0;
                    y = (srcImage.Height / 2) - (waterMark.Height / 2);
                    break;
                case ImagePostion.MiddleMost:
                    x = (srcImage.Width / 2) - (waterMark.Width / 2);
                    y = (srcImage.Height / 2) - (waterMark.Height / 2);
                    break;
                case ImagePostion.MiddleRight:
                    x = srcImage.Width - waterMark.Width;
                    y = (srcImage.Height / 2) - (waterMark.Height / 2);
                    break;
                case ImagePostion.BottomLeft:
                    x = 0;
                    y = srcImage.Height - waterMark.Height;
                    break;
                case ImagePostion.BottomCenter:
                    x = (srcImage.Width / 2) - (waterMark.Width / 2);
                    y = srcImage.Height - waterMark.Height;
                    break;
                case ImagePostion.BottonRight:
                    x = srcImage.Width - waterMark.Width;
                    y = srcImage.Height - waterMark.Height;
                    break;
                default:
                    break;
            }
            #endregion

            srcImage = DrawWaterMark(srcImage, waterMark, x, y);

            return srcImage;
        }
        #endregion

        #region Image Postion + Alpha Rate
        /**/
        /// <summary>
        /// Draw WaterMark to Src Image
        /// </summary>
        /// <param name="srcImage">Src Image</param>
        /// <param name="waterMark">WaterMark Image</param>
        /// <param name="oPosition">WaterMark's position</param>
        /// <param name="alphaRate">WaterMark's alpha rate, 0 to 255, 0 means total transparent, 255 means don't transparent</param>
        /// <returns>Image</returns>
        public Image DrawWaterMark(Image srcImage, Image waterMark, ImagePostion oPosition, int alphaRate)
        {
            int x = 0;
            int y = 0;

            #region Switch Postion get X and Y
            switch (oPosition)
            {
                case ImagePostion.TopLeft:
                    x = 0;
                    y = 0;
                    break;
                case ImagePostion.TopCenter:
                    x = (srcImage.Width / 2) - (waterMark.Width / 2);
                    y = 0;
                    break;
                case ImagePostion.TopRight:
                    x = srcImage.Width - waterMark.Width;
                    y = 0;
                    break;
                case ImagePostion.MiddleLeft:
                    x = 0;
                    y = (srcImage.Height / 2) - (waterMark.Height / 2);
                    break;
                case ImagePostion.MiddleMost:
                    x = (srcImage.Width / 2) - (waterMark.Width / 2);
                    y = (srcImage.Height / 2) - (waterMark.Height / 2);
                    break;
                case ImagePostion.MiddleRight:
                    x = srcImage.Width - waterMark.Width;
                    y = (srcImage.Height / 2) - (waterMark.Height / 2);
                    break;
                case ImagePostion.BottomLeft:
                    x = 0;
                    y = srcImage.Height - waterMark.Height;
                    break;
                case ImagePostion.BottomCenter:
                    x = (srcImage.Width / 2) - (waterMark.Width / 2);
                    y = srcImage.Height - waterMark.Height;
                    break;
                case ImagePostion.BottonRight:
                    x = srcImage.Width - waterMark.Width;
                    y = srcImage.Height - waterMark.Height;
                    break;
                default:
                    break;
            }
            #endregion

            srcImage = DrawWaterMark(srcImage, waterMark, x, y, alphaRate);

            return srcImage;
        }

        #endregion


        #region Add Characters To Image

        #region Text X, Y
        /**/
        /// <summary>
        /// Draw Characters to Image
        /// </summary>
        /// <param name="srcImage">Src Image</param>
        /// <param name="text">Text to add</param>
        /// <param name="textFont">Font of Text</param>
        /// <param name="textSize">Size of Text</param>
        /// <param name="textColor">Color of Text</param>
        /// <param name="x">Text's Location X</param>
        /// <param name="y">Text's Location Y</param>
        /// <returns>Image</returns>
        public Image DrawCharacter(Image srcImage, string text, string textFont, float textSize, Color textColor, float x, float y)
        {
            Graphics g = Graphics.FromImage(srcImage);
            Font f = new Font(textFont, textSize);
            Brush b = new SolidBrush(textColor);

            g.DrawString(text, f, b, x, y);
            g.Dispose();

            return srcImage;
        }

        #endregion

        #region Text Postion
        /**/
        /// <summary>
        /// Draw Characters to Image
        /// </summary>
        /// <param name="srcImage">Src Image</param>
        /// <param name="text">Text to add</param>
        /// <param name="textFont">Font of Text</param>
        /// <param name="textSize">Size of Text</param>
        /// <param name="textColor">Color of Text</param>
        /// <param name="oPosition">Position of Text</param>
        /// <returns>Image</returns>
        public Image DrawCharacter(Image srcImage, string text, string textFont, float textSize, Color textColor, ImagePostion oPosition)
        {
            float x = 0;
            float y = 0;

            //Get the text's Width and Height
            Bitmap bm = new Bitmap(10, 10);
            Graphics g = Graphics.FromImage(bm);
            Font f = new Font(textFont, textSize);
            SizeF size = g.MeasureString(text, f);
            //float textLength = text.Length * textSize;
            float textWidth = size.Width;
            float textHeight = size.Height;

            #region Switch Postion get X and Y

            switch (oPosition)
            {
                case ImagePostion.TopLeft:
                    x = 0;
                    y = 0;
                    break;
                case ImagePostion.TopCenter:
                    x = (srcImage.Width / 2) - (textWidth / 2);
                    y = 0;
                    break;
                case ImagePostion.TopRight:
                    x = srcImage.Width - textWidth;
                    y = 0;
                    break;
                case ImagePostion.MiddleLeft:
                    x = 0;
                    y = (srcImage.Height / 2) - (textHeight / 2);
                    break;
                case ImagePostion.MiddleMost:
                    x = (srcImage.Width / 2) - (textWidth / 2);
                    y = (srcImage.Height / 2) - (textHeight / 2);
                    break;
                case ImagePostion.MiddleRight:
                    x = srcImage.Width - textWidth;
                    y = (srcImage.Height / 2) - (textHeight / 2);
                    break;
                case ImagePostion.BottomLeft:
                    x = 0;
                    y = srcImage.Height - textSize;
                    break;
                case ImagePostion.BottomCenter:
                    x = (srcImage.Width / 2) - (textWidth / 2);
                    y = srcImage.Height - textHeight;
                    break;
                case ImagePostion.BottonRight:
                    x = srcImage.Width - textWidth;
                    y = srcImage.Height - textHeight;
                    break;
                default:
                    break;
            }
            #endregion

            srcImage = DrawCharacter(srcImage, text, textFont, textSize, textColor, x, y);

            return srcImage;
        }

        #endregion

        #endregion

        #region Add Border to Image

        #region BorderStyle

        /// <summary>
        /// Add Border
        /// </summary>
        /// <param name="srcImage"></param>
        /// <param name="borderColor"></param>
        /// <param name="borderWidth"></param>
        /// <param name="borderStyle"></param>
        /// <returns></returns>
        public Image AddBorder(Image srcImage, Color borderColor, int borderWidth, BorderStyle borderStyle)
        {
            Graphics g = Graphics.FromImage(srcImage);

            Pen oPen = new Pen(borderColor, borderWidth);

            int x = 0;
            int y = 0;
            int width = 0;
            int height = 0;

            switch (borderStyle)
            {
                case BorderStyle.All:
                    AddBorder(srcImage, borderColor, borderWidth);
                    return srcImage;
                case BorderStyle.Top:
                    width = srcImage.Width;
                    height = borderWidth;
                    break;
                case BorderStyle.Left:
                    width = borderWidth;
                    height = srcImage.Height;
                    break;
                case BorderStyle.Right:
                    x = srcImage.Width - borderWidth;
                    width = borderWidth;
                    height = srcImage.Height;
                    break;
                case BorderStyle.Bottom:
                    y = srcImage.Height - borderWidth;
                    width = srcImage.Width;
                    height = borderWidth;
                    break;
            }

            g.DrawRectangle(oPen, x, y, width, height);

            return srcImage;
        }
        #endregion

        #region Border Style Default All

        /// <summary>
        /// 
        /// </summary>
        /// <param name="srcImage"></param>
        /// <param name="borderColor"></param>
        /// <param name="borderWidth"></param>
        /// <returns></returns>
        public Image AddBorder(Image srcImage, Color borderColor, int borderWidth)
        {
            Graphics g = Graphics.FromImage(srcImage);

            Pen oPen = new Pen(borderColor, borderWidth);

            int x = 0;
            int y = 0;
            int width = 0;
            int height = 0;

            //依次按照上左右下的顺序开始绘制边框

            //Top
            width = srcImage.Width;
            height = borderWidth;
            g.DrawRectangle(oPen, x, y, width, height);

            //Left
            width = borderWidth;
            height = srcImage.Height;
            g.DrawRectangle(oPen, x, y, width, height);

            //Right
            x = srcImage.Width - borderWidth;
            width = borderWidth;
            height = srcImage.Height;
            g.DrawRectangle(oPen, x, y, width, height);

            //Bottom
            x = 0;
            y = srcImage.Height - borderWidth;
            width = srcImage.Width;
            height = borderWidth;
            g.DrawRectangle(oPen, x, y, width, height);

            return srcImage;
        }
        #endregion

        #endregion

        #region ReSize the Image

        //通过缩列图的方式对图片进行缩放
        /// <summary>
        /// 通过缩列图的方式对图片进行缩放
        /// </summary>
        /// <param name="srcImage"></param>
        /// <param name="NewImageSize"></param>
        /// <returns></returns>
        public Image GetThumbnailImage(Image srcImage, Size NewImageSize)
        {
            return srcImage.GetThumbnailImage(NewImageSize.Width, NewImageSize.Height, null, IntPtr.Zero);
        }

        //通过对图片的重绘进行缩放
        /// <summary>
        /// 通过对图片的重绘进行缩放
        /// </summary>
        /// <param name="srcImage"></param>
        /// <param name="NewImageSize"></param>
        /// <returns></returns>
        public Image ReSizeImage(Image srcImage, Size NewImageSize)
        {
            if (srcImage == null) return null;
            Bitmap bitmap = null;

            Graphics graphics = null;

            try
            {
                int width = NewImageSize.Width;
                int height = NewImageSize.Height;

                bitmap = new Bitmap(NewImageSize.Width, NewImageSize.Height);

                bitmap.SetResolution(srcImage.HorizontalResolution, srcImage.VerticalResolution);

                //从指定的 Image 对象创建新 Graphics 对象
                graphics = Graphics.FromImage(bitmap);

                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.CompositingQuality = CompositingQuality.AssumeLinear;
               
                //增加抗锯齿处理(感觉没什么太好的效果)
                graphics.SmoothingMode = SmoothingMode.AntiAlias;

                //清除整个绘图面并以透明背景色填充
                graphics.Clear(Color.Transparent);

                Point ImagePoint = new Point(0, 0);

                //在指定位置并且按指定大小绘制 原图片 对象
                graphics.DrawImage(srcImage, new Rectangle(ImagePoint, NewImageSize));

                //srcImage =Rtl(bitmap) ;

                srcImage = (Image)bitmap;



            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                //bitmap.Dispose();

                //graphics.Dispose();
            }

            return srcImage;
        }

        #endregion

        #region Images Convert

        #region Image Convert To Emf

        /// <summary>
        /// 
        /// </summary>
        /// <param name="srcImage"></param>
        /// <returns></returns>
        public Metafile Image2Emf(Image srcImage)
        {
            if (srcImage == null) return null;
            Bitmap bitmap = null;

            Graphics graphics = null;

            Metafile dscMeta = null;

            Graphics gsMeta = null;

            try
            {
                bitmap = new Bitmap(srcImage);

                // new metafile
                gsMeta = Graphics.FromImage(bitmap);

                dscMeta = new Metafile(gsMeta.GetHdc(), EmfType.EmfPlusDual);


                // draw image to metafile
                graphics = Graphics.FromImage(dscMeta);
                graphics.DrawImage(bitmap, 0, 0, bitmap.Width, bitmap.Height);

            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                graphics.Dispose();
                dscMeta.Dispose();
                bitmap.Dispose();
            }

            return dscMeta;
        }

        #endregion


        #region Image Convert To Icon
        /// <summary>
        /// 
        /// </summary>
        /// <param name="srcImage"></param>
        /// <returns></returns>

        public Icon Image2Icon(Image srcImage)
        {
            if (srcImage == null) return null;

            IconConverter convert = new IconConverter();

            Icon descIcon = (Icon)convert.ConvertTo(srcImage, typeof(Icon));

            return descIcon;
        }

        #endregion

        #endregion

        #region Public Enum

        #region Positon Enum
        /**/
        /// <summary>
        /// Water Mark Positon Enum, Total 9 positions
        /// </summary>
        public enum ImagePostion
        {
            /// <summary>
            /// Left
            /// </summary>
            TopLeft,
            /// <summary>
            /// Center
            /// </summary>
            TopCenter,
            /// <summary>
            /// Right
            /// </summary>
            TopRight,
            /// <summary>
            /// MiddleLeft
            /// </summary>
            MiddleLeft,
            /// <summary>
            /// MiddleRight
            /// </summary>
            MiddleMost,
            /// <summary>
            /// MiddleRight
            /// </summary>
            MiddleRight,
            /// <summary>
            /// BottomLeft
            /// </summary>
            BottomLeft,
            /// <summary>
            /// BottomCenter
            /// </summary>
            BottomCenter,
            /// <summary>
            /// BottonRight
            /// </summary>
            BottonRight
        }
        #endregion

        #region Border Style Enum
        /**/
        /// <summary>
        /// Border Style
        /// </summary>
        public enum BorderStyle
        {
            /// <summary>
            /// All
            /// </summary>
            All,
            /// <summary>
            /// Top
            /// </summary>
            Top,
            /// <summary>
            /// Left
            /// </summary>
            Left,
            /// <summary>
            /// Right
            /// </summary>
            Right,
            /// <summary>
            /// Bottom
            /// </summary>
            Bottom
        }
        #endregion

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="bm"></param>
        /// <returns></returns>
        public static Image Rtl(Bitmap bm)
        {
            IntPtr hBitmap, ppvBits;
            BITMAPINFO bmi = new BITMAPINFO();

            bmi.biSize = 40;			// Needed for RtlMoveMemory()
            bmi.biBitCount = 32;		// Number of bits
            bmi.biPlanes = 1;			// Number of planes
            bmi.biWidth = bm.Width;		// Width of our new bitmap
            bmi.biHeight = bm.Height;	// Height of our new bitmap
            bm.RotateFlip(RotateFlipType.RotateNoneFlipY);	// Required due to the way bitmap is copied
            hBitmap = CreateDIBSection(new IntPtr(0), bmi, 0, out ppvBits, new IntPtr(0), 0);
            BitmapData bitmapData = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            RtlMoveMemory(ppvBits, bitmapData.Scan0, bm.Height * bitmapData.Stride); // copies the bitmap
            bm.UnlockBits(bitmapData);
            return Image.FromHbitmap(hBitmap);
        }

    }
}
